Proxy 与 Reflect 的使用
如果说 Object.defineProperty
是对象的属性代理,
那 Proxy
与 Reflect
就是针对整个对象的代理。
通过使用这两个函数,我们可以对对象进行更精细,复杂的劫持。
Proxy 语法以及参数
const p = new Proxy(target, handler);
参数 | 说明 |
---|---|
target | 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 |
handler | 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。 |
handler 的方法
如果定义了相应的劫持器,则当调用相应 API 的时候会触发该劫持器,如果没定义则会保持默认
Proxy 函数 | 方法含义 |
---|---|
getPrototypeOf 对应 Object.getPrototypeOf 方法的捕捉器 | Object.getPrototypeOf 为获取对象的原型 |
setPrototypeOf 对应 Object.setPrototypeOf 方法的捕捉器 | Object.setPrototypeOf 为设置对象的原型 |
isExtensible 对应 Object.isExtensible 方法的捕捉器 | Object.isExtensible 为检测该对象是否是可拓展的,即是否可以添加新属性。 |
preventExtensions 对应 Object.preventExtensions 方法的捕捉器 | Object.preventExtensions 会让传入的对象变成不可拓展对象,即不能添加新的属性 |
getOwnPropertyDescriptor 对应 Object.getOwnPropertyDescriptor 方法的捕捉器 | Object.getOwnPropertyDescriptor 为获取对象属性的描述符,与 Object.defineProperty 所设置的描述符一致 |
defineProperty 对应 Object.defineProperty 方法的捕捉器 | Object.defineProperty 会修改对象的属性以及描述符,使其修改原属性或新增属性 |
has 对应 in 运算符的捕捉器 | 当指定的属性在指定的对象或其原型链中,调用 in 运算符会返回 true |
get 对应属性读取操作的捕捉器 | 属性读取操作的捕捉器 |
set 对应属性设置操作的捕捉器 | 属性设置操作的捕捉器 |
ownKeys 对应 Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。 | Object.getOwnPropertyNames 为返回自身的所有属性的属性名,而 Object.getOwnPropertySymbols 返回的是 Symbol 属性数组,Symbol 代表一个独一无二的值 |
apply 对应函数调用操作的捕捉器 | 如果对 proxy 进行调用会触发该捕捉器 |
construct 对应 new 操作符的捕捉器。 | 当对 proxy 进行 new 操作时会触发该捕捉器 |
handler
的约束问题Proxy
的捕捉器函数存在一定的约束,具体可以在 MDN
查询,核心观点其实就是单纯的不允许 Proxy
代理的对象与原对象不一致,如原对象是不可拓展的,那就不可以在 Proxy
返回可拓展,否则就违背了原对象的含义。
Reflect
介绍
Reflect
与 Proxy
都同时在 ES2015
标准中,算是与 Proxy
一起的伴生 API
。
他是一个内置的对象,提供的方法与 Proxy
的 Handler
中是相同的。
但是他不是一个函数,因此是不可构造的,我们只可以使用他的静态方法。
为什么存在 Reflect
?
通常我们将它与 Proxy
进行联合使用,在进行劫持后调用原方法,那为什么不直接操作对象呢?
这点我认为存在两个原因
-
目前暴露了一些核心的
api
供我们调用,但是未来可能隐藏掉这些api
,通过Reflect
才能调用。 -
统一操作的过程,如果我们不使用
Reflect
提供的函数,而使用操作的函数进行对象操作,那有一部分对象操作失败会报出异常,有一部分会报出null
等等,返回值并不统一,而Reflect
相对统一,比如曾经错误会报出异常的函数,在Reflect
内会返回false
,使用Reflect
我们可以对各种函数有一个更统一的返回值以及处理。
Reflect 的函数有哪些?
Reflect 函数 | 方法含义 |
---|---|
Reflect.apply(target, thisArgument, argumentsList) | 对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。 |
Reflect.construct(target, argumentsList[, newTarget]) | 对构造函数进行 new 操作,相当于执行 new target(...args) |
Reflect.defineProperty(target, propertyKey, attributes) | 与 Object.defineProperty() 类似。如果设置成功就会返回 true |
Reflect.deleteProperty(target, propertyKey) | 函数的 delete 操作符,相当于执行 delete target[name] |
Reflect.get(target, propertyKey[, receiver]) | 获取对象身上某个属性的值,类似于 target[name] |
Reflect.getOwnPropertyDescriptor(target, propertyKey) | 类似于 Object.getOwnPropertyDescriptor() 。如果对象中存在该属性,则返回对应的属性描述符, 否则返回 undefined |
Reflect.getPrototypeOf(target) | 与 Object.getPrototypeOf 获取对象的原型的函数行为类似 |
Reflect.has(target, propertyKey) | 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同 |
Reflect.isExtensible(target) | 类似于 Object.isExtensible() ,判断对象是否是可拓展的对象 |
Reflect.ownKeys(target) | 返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys() , 但不会受 enumerable 影响) |
Reflect.preventExtensions(target) | 类似于 Object.preventExtensions() , 让传入的对象变成不可拓展对象 |
Reflect.set(target, propertyKey, value[, receiver]) | 将值分配给属性的函数,返回一个 Boolean ,等价于属性赋值 |
Reflect.setPrototypeOf(target, prototype) | 设置对象原型的函数,返回一个 Boolean |